import json
import datetime
import math

from django import http
from django.core.cache import cache

from django.db.models import Q

from django.db import transaction
from django.shortcuts import render

# Create your views here.
from django.views import View

from apps.homes.models import Area, House, Facility, HouseImage
from apps.orders.models import Order
from django.conf import settings

from ihome_pro.utils.AliFileStorage import upload_image
from ihome_pro.utils.ImageChecking import image_file
from ihome_pro.utils.LoginRequireJson import LoginRequiredJsonMixin
from ihome_pro.utils.qiniu_storage import storage
from .utils import rented_house


class AreaView(View):
    """城区列表"""

    def get(self, request):
        """
        城区列表业务逻辑实现
        :param request:
        :return:
        """
        # 获取城区信息
        # 获取缓存
        areas = cache.get('area_list')
        # 判断城区列表是否存在
        if areas:
            return http.JsonResponse({'errno': 0, 'errmsg': '获取成功', 'data': areas})

        try:
            area_mobile_list = Area.objects.all()
        except Area.DoesNotExist:
            return http.JsonResponse({'errno': 400, "errmsg": '数据库错误'})
        # 创建城区列表
        areas = []
        for area in area_mobile_list:
            areas.append({
                "aid": area.id,
                "aname": area.name
            })
        # 设置缓存
        cache.set('area_list', areas, 3600)
        # 返回响应
        return http.JsonResponse({'errno': 0, 'errmsg': '获取成功', 'data': areas})


class SendHouseView(View):
    """发布房源"""

    def post(self, request):
        """
        发布房源业务逻辑实现
        :param request:
        :return:
        """
        user = request.user
        # 获取参数
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')
        price = json_dict.get('price')
        area_id = json_dict.get('area_id')
        address = json_dict.get('address')
        room_count = json_dict.get('room_count')
        acreage = json_dict.get('acreage')
        unit = json_dict.get('unit')
        capacity = json_dict.get('capacity')
        beds = json_dict.get('beds')
        deposit = json_dict.get('deposit')
        min_days = json_dict.get('min_days')
        max_days = json_dict.get('max_days')

        # 校验参数
        # 判断参数是否完整
        if not all(
                [title, price, area_id, address, room_count, acreage, unit, capacity, beds, deposit, min_days,
                 max_days]):
            return http.JsonResponse({'errno': 400, 'errmsg': '参数不完整'})
        # 对参数的合理性进行校验
        if int(price) < 0:
            return http.JsonResponse({'errno': 400, 'errmsg': '价格不能为负'})
        try:
            area = Area.objects.get(id=area_id)
        except:
            return http.JsonResponse({'errno': 400, 'errmsg': 'area_id不合理'})
        if int(room_count) < 0:
            return http.JsonResponse({'errno': 400, 'errmsg': '房间数不能为负'})
        if int(acreage) < 0:
            return http.JsonResponse({'errno': 400, 'errmsg': '房屋面积不能为负'})
        if int(capacity) < 0:
            return http.JsonResponse({'errno': 400, 'errmsg': '房屋宜住的人数不能为负'})
        if int(deposit) < 0:
            return http.JsonResponse({'errno': 400, 'errmsg': '押金不能为负'})
        if int(max_days) < 0 or int(min_days) < 0:
            return http.JsonResponse({'errno': 400, 'errmsg': '可入住天数不能为负'})
        if int(max_days) != 0:
            if int(max_days) < int(min_days):
                return http.JsonResponse({'errno': 400, 'errmsg': '最大天数不能小于最小天数'})

        try:
            price = int(float(price) * 100)
            deposit = int(float(deposit) * 100)
        except:
            return http.JsonResponse({'errno': 400, 'errmsg': '参数错误'})
        # 判断地址是否存在
        try:
            Area.objects.get(id=area_id)
        except Area.DoesNotExist:
            return http.JsonResponse({'errno': 400, 'errmsg': '地址不存在'})

        try:
            if int(max_days) < int(min_days) and int(max_days) != 0:
                return http.JsonResponse({'errno': 400, 'errmsg': '最大天数少于最小天数'})
        except:
            return http.JsonResponse({'errno': 400, 'errmsg': '参数错误'})

        # 开启事物
        with transaction.atomic():
            # 设置事物保存点
            save_point = transaction.savepoint()
            # 保存房源信息
            try:
                homeinfo = House.objects.create(
                    title=title,
                    price=price,
                    area_id=area_id,
                    address=address,
                    room_count=room_count,
                    acreage=acreage,
                    unit=unit,
                    capacity=capacity,
                    beds=beds,
                    deposit=deposit,
                    min_days=min_days,
                    max_days=max_days,
                    user_id=user.id,
                )

                # 设置设施信息
                facilities = json_dict.get('facility')
                if facilities:
                    facility_list = Facility.objects.filter(id__in=facilities)
                    for facility in facility_list:
                        homeinfo.facility.add(facility)
            except:
                transaction.savepoint_rollback(save_point)
                return http.JsonResponse({'errno': 400, 'errmsg': '数据库错误'})

            transaction.savepoint_commit(save_point)

        # 返回响应
        return http.JsonResponse({
            'errno': 0,
            'errmsg': '发布成功',
            'data': {
                "house_id": homeinfo.id
            }})

    def get(self, request):
        """
        房屋数据搜索
        :param request:
        :return:
        """
        # 获取参数
        aid = request.GET.get('aid')
        start_day = request.GET.get('sd')
        end_day = request.GET.get('ed')
        sort_key = request.GET.get('sk', 'new')
        page = request.GET.get('p', '1')

        if aid:
            try:
                area = Area.objects.get(id=aid)
            except Exception as e:
                return http.JsonResponse({"errmsg": "参数aid错误", "errno": "4103"})

        if start_day:
            try:
                sd = datetime.datetime.strptime(start_day, '%Y-%m-%d')
            except Exception as e:
                return http.JsonResponse({"errmsg": "参数sd错误", "errno": "4103"})

        if end_day:
            try:
                ed = datetime.datetime.strptime(end_day, '%Y-%m-%d')
            except Exception as e:
                return http.JsonResponse({"errmsg": "参数ed错误", "errno": "4103"})

        if sort_key not in ['new', 'booking', 'price-inc', 'price-des']:
            return http.JsonResponse({"errmsg": "参数sort_key错误", "errno": "4103"})

        if page:
            try:
                page = int(page)
            except Exception as e:
                return http.JsonResponse({"errmsg": "参数page错误", "errno": "4103"})

        try:
            houses = House.objects.all()
        except Exception as e:
            return http.JsonResponse({"errmsg": "数据库查询错误", "errno": "4001"})

        if aid:
            try:
                houses = houses.filter(area_id=aid)
            except Exception as e:
                return http.JsonResponse({"errmsg": "数据库查询错误", "errno": "4001"})

        if all([start_day, end_day]):
            try:
                live_days = (ed - sd).days
                houses = houses.filter(Q(min_days__lte=live_days, max_days__gte=live_days) | Q(max_days=0))
            except Exception as e:
                return http.JsonResponse({"errmsg": "数据库查询错误", "errno": "4001"})

        if start_day or end_day:
            house_rent = rented_house(datetime.datetime.strptime(start_day, '%Y-%m-%d'),
                                      datetime.datetime.strptime(end_day, '%Y-%m-%d'))

            try:
                houses = houses.exclude(id__in=house_rent)
            except Exception:
                return http.JsonResponse({"errmsg": "数据库查询错误", "errno": "4001"})

        if sort_key == 'new':  # 最新上线
            houses = houses.order_by('-update_time')
        elif sort_key == 'booking':  # 入住最多
            houses = houses.order_by('-order_count')
        elif sort_key == 'price-inc':  # 价格由低到高
            houses = houses.order_by('price')
        else:  # 价格由高到低
            houses = houses.order_by('-price')

        try:
            house_list = []
            houses_count = houses.count()
            start_index = 5 * (page - 1)
            if houses_count < 5 * page:
                end_index = houses_count
            else:
                end_index = 5 * page
            try:
                avatar_url = houses.user.avatar
            except:
                avatar_url = ''
            for house in houses[start_index: end_index]:
                house_list.append({
                    "address": house.address,
                    "area_name": house.area.name,
                    "ctime": house.update_time,
                    "house_id": house.id,
                    "img_url": settings.IMAGE_URL + house.index_image_url,
                    "order_count": house.order_count,
                    "price": house.price,
                    "room_count": house.room_count,
                    "title": house.title,
                    "user_avatar": avatar_url
                })

        except Exception as e:
            return http.JsonResponse({'errno': 4001, 'errmsg': '数据库读写错误'})

        return http.JsonResponse({
            "data": {
                "houses": house_list,
                "total_page": math.ceil(houses_count / 5)
            },
            "errmsg": "请求成功",
            "errno": "0"
        })


class HouseImageView(LoginRequiredJsonMixin, View):
    """上传房源图片"""

    def post(self, request, house_id):
        """
        上传房源图片业务逻辑实现
        :param request:
        :param house_id: 房屋ID
        :return:
        """
        # 接受参数
        house_image = request.FILES.get('house_image')
        # 校验参数
        if not house_image:
            return http.JsonResponse({'errno': 400, 'errmsg': '参数错误'})
        if not image_file(house_image):
            return http.JsonResponse({'errno': 400, 'errmsg': '上传不是图片'})

        try:
            house = House.objects.get(id=house_id)
        except:
            return http.JsonResponse({'errno': 400, 'errmsg': '该房间不存在'})

        image_name = house_image.name
        image_data = house_image.read()
        try:
            image_url = upload_image(image_name, image_data)
            # image_url = storage(image_data)
        except:
            return http.JsonResponse({'errno': 400, 'errmsg': '图片上传失败'})

        try:
            if not house.index_image_url:
                house.index_image_url = image_url
                house.save()

            house_image = HouseImage()
            house_image.house = house
            house_image.url = image_url
            house_image.save()

        except:
            return http.JsonResponse({'errno': 400, 'errmsg': '数据库错误'})

        return http.JsonResponse({
            'data': {
                'url': settings.IMAGE_URL + image_url
            },
            'errno': '0',
            'errmsg': '图片上传成功'
        })


class HouseListView(LoginRequiredJsonMixin, View):
    """房屋列表"""

    def get(self, request):
        """房屋列表业务逻辑实现"""
        # 获取登录用户
        user = request.user
        try:
            houses = House.objects.filter(user_id=user.id)
        except:
            return http.JsonResponse({'errno': 400, 'errmsg': '数据库错误'})

        # 构造房屋列表
        houses_list = []
        for house in houses:
            # try:
            #     user_avatar = house.user.avatar.url
            # except:
            #     user_avatar = None
            houses_list.append({
                "address": house.address,
                "area_name": house.area.name,
                "ctime": house.create_time.strftime("%Y-%m-%d"),
                "house_id": house.id,
                "img_url": settings.IMAGE_URL + house.index_image_url,
                "order_count": house.order_count,
                "price": house.price,
                "room_count": house.room_count,
                "title": house.title,
                "user_avatar": house.user.avatar
            })
        # 返回响应
        return http.JsonResponse({
            'data': {'houses': houses_list},
            'errno': 0,
            'errmsg': 'ok'
        })


class HouseRecommend(View):
    """首页房屋推荐"""

    def get(self, request):
        """
        首页房屋推荐业务逻辑实现
        :param request:
        :return:
        """

        # 获取房屋信息
        try:
            houses = House.objects.order_by("-create_time")[0:5]
        except:
            return http.JsonResponse({'errno': 400, 'errmsg': '数据库错误'})
        # 构造首页房屋推荐列表
        house_recommend_list = []
        for house in houses:
            house_recommend_list.append({
                "house_id": house.id,
                "img_url": settings.IMAGE_URL + house.index_image_url,
                "title": house.title
            })

        # 返回响应
        return http.JsonResponse({
            'data': house_recommend_list,
            'errno': 0,
            'errmsg': 'ok'
        })


class HouseDetail(View):
    """房屋详情"""

    def get(self, request, house_id):
        """房屋详情页面的业务逻辑实现"""
        # 获取当前用户
        user = request.user
        if not user.is_authenticated:
            user_id = -1
        else:
            user_id = user.id
        try:
            house = House.objects.get(id=house_id)
        except:
            return http.JsonResponse({'errno': 400, 'errmsg': '数据库错误'})

        # 将详细信息转换为字典数据
        house_dict = {
            "hid": house.id,
            "user_id": house.user.id,
            "user_name": house.user.username,
            "user_avatar": house.user.avatar if house.user.avatar else "",
            "title": house.title,
            "price": house.price,
            "address": house.address,
            "room_count": house.room_count,
            "acreage": house.acreage,
            "unit": house.unit,
            "capacity": house.capacity,
            "beds": house.beds,
            "deposit": house.deposit,
            "min_days": house.min_days,
            "max_days": house.max_days,
        }

        # 房屋图片
        img_urls = []
        for image in house.houseimage_set.all():
            img_urls.append(image.url)
        house_dict["img_urls"] = img_urls

        # 房屋设施1100
        facilities = []
        for facility in house.facility.all():
            facilities.append(facility.id)
        house_dict["facilities"] = facilities

        # 评论信息
        comments = []
        orders = Order.objects.filter(house=house, status=Order.ORDER_STATUS["COMPLETE"],
                                      comment__isnull=False).order_by("-update_time")[0:30]
        for order in orders:
            comment = {
                "comment": order.comment,  # 评论的内容
                "user_name": order.user.username if order.user.username != order.user.mobile else "匿名用户",  # 发表评论的用户
                "ctime": order.update_time.strftime("%Y-%m-%d %H:%M:%S")  # 评价的时间
            }
            comments.append(comment)
        house_dict["comments"] = comments

        return http.JsonResponse({
            'data': {'house': house_dict, 'user_id': user.id},
            'errno': 0,
            'errmsg': 'ok'
        })
